﻿using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class AssociationSwapperSpecification {
        [Test]
        public void ShouldSwapTwoCompositeTermsThatHaveSameName () {
            var i1 = new IntegerTerm (1, null);
            var i2 = new IntegerTerm (2, null);
            var i3 = new IntegerTerm (3, null);
            var i4 = new IntegerTerm (4, null);
            var i5 = new IntegerTerm (5, null);

            var outer = new CompositeTerm ("name", null);
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);
            var outerSinfo = new SourceInformation (null, 0, 10);
            outer.SourceInformation = outerSinfo;

            var inner = new CompositeTerm ("name", null);
            outer.Add ("last", inner, false);

            inner.Add ("first", i3, false);
            inner.Add ("middle", i4, false);
            inner.Add ("last", i5, false);
            var innerSinfo = new SourceInformation (null, 5, 10);
            inner.SourceInformation = innerSinfo;

            var swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (inner, result);
            Assert.AreSame (outerSinfo, inner.SourceInformation);
            Assert.AreSame (outer, result.SubTerms ["first"]);
            Assert.AreSame (innerSinfo, outer.SourceInformation);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (i3, outer.SubTerms ["last"]);
            Assert.AreSame (i4, inner.SubTerms ["middle"]);
            Assert.AreSame (i5, inner.SubTerms ["last"]);
        }

        [Test]
        public void ShouldReturnOuterIfNamesDoNotMatch () {
            var i1 = new IntegerTerm (1, null);
            var i2 = new IntegerTerm (2, null);
            var i3 = new IntegerTerm (3, null);
            var i4 = new IntegerTerm (4, null);
            var i5 = new IntegerTerm (5, null);

            var outer = new CompositeTerm ("name1", null);
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);

            var inner = new CompositeTerm ("name2", null);
            outer.Add ("last", inner, false);

            inner.Add ("first", i3, false);
            inner.Add ("middle", i4, false);
            inner.Add ("last", i5, false);

            var swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (outer, result);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (inner, outer.SubTerms ["last"]);
            Assert.AreSame (i3, inner.SubTerms ["first"]);
            Assert.AreSame (i4, inner.SubTerms ["middle"]);
            Assert.AreSame (i5, inner.SubTerms ["last"]);
        }

        [Test]
        public void ShouldReturnOuterIfLastFromInnerIsNotCompositeTerm () {
            var i1 = new IntegerTerm (1, null);
            var i2 = new IntegerTerm (2, null);
            var i3 = new IntegerTerm (3, null);
            var i4 = new IntegerTerm (4, null);
            var i5 = new IntegerTerm (5, null);

            var outer = new CompositeTerm ("name", null);
            outer.Add ("first", i1, false);
            outer.Add ("middle", i2, false);

            outer.Add ("last", i3, false);

            var swapper = new AssociationSwapper ("first", "last");

            var result = swapper.Swap (outer);

            Assert.AreSame (outer, result);
            Assert.AreSame (i1, outer.SubTerms ["first"]);
            Assert.AreSame (i2, outer.SubTerms ["middle"]);
            Assert.AreSame (i3, outer.SubTerms ["last"]);
        }
    }
}